home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SuperHack
/
SuperHack CD.bin
/
CODING
/
PC
/
SNIP9611.ZIP
/
DIRPORT.HOW
< prev
next >
Wrap
Text File
|
1996-11-24
|
10KB
|
229 lines
+++Date last modified: 24-Nov-1996
How to Use the Portable Directory Processing Functions in DIRPORT.H
===================================================================
Background:
-----------
All common PC operating systems (OS's) except Linux and FreeBSD are
decendents of PC/MS-DOS and, as such, all use similar methods of processing
directories. This is well established as a simple two-call sequence: 1) find
the first file matching a given file specification; 2) find subsequent files
matching the same specification. The file specification in either case may
contain wildcards and/or directory path information as well as specific file
attributes.
Where the various OS's and compilers diverge is in the details of this
process. Different OS's, although descended from DOS, have different file
types and different ways of masking which type of file(s) to process. Even
within the same OS, different compilers have adopted different naming
conventions for their (inherently non-portable) functions to call the
underlying OS functionality.
At this point, it may be worthwhile to note that various Unix ports and
clones often support the Posix-compliant directory processing functions,
opendir(), readdir(), closedir(), seekdir(), and rewinddir(). A set of such
functions is provided in SNIPPETS for those wishing to use these functions.
The obvious advantage is portability. The disadvantage is that resulting
programs will be larger and run more slowly when using these functions. The
degree of impact will depend on the specifics of your application and
environment, and may range from imperceptible to significant. The underlying
cause is that the Posix functions must still be translated into the find
first/find next calls supported by popular PC OS's.
The DIRPORT.H header file in SNIPPETS supports all major PC OS's (except for
the Unix-ish ones) and compilers. Those already used to using the DOS
interface find first/next calls will find it easy to use. The big problem is
that, as support for more OS's and compilers has been added, DIRPORT.H has
become somewhat unreadable, even to experienced programmers. This text is
therefore a guide to using DIRPORT.H
The basic concepts:
-------------------
When finding the first file in a directory matching a given file
specification, the OS needs to know three things:
1. The filename specification, which may contain wildcards and/or directory
information.
2. The type of file. This is typically specified as an integral data type
with bit-mapped file attributes.
3. A location where the resulting information will be stored in case the
specified file can be found.
The header file must therefore specify 4 items:
1. A function to call to find the first file.
2. A function to call to find subsequent files matching the specification.
3. Defined constants for specific file attributes.
4. A structure defining the data returned from the functions.
In addition, due to differences in PC OS's, one other function must be
provided to close directory processing sessions.
The implementation:
-------------------
The structure used to process directory data is typedef'ed in DIRPORT.H as
type DOSFileData. This is really all the user needs to know about it since
all access to the elements of a DOSFileData structure is via macros defined
in DIRPORT.H.
The function to find the first matching file is defined in DIRPORT,H as...
FIND_FIRST(spec,attr,buf);
...where "spec" is the filename specification, "attr" is the bit mapped file
attribute mask, and "buf" is the address of the DOSFileData structure to
receive information if a matching file can be found. FIND_FIRST returns 0 if
successful, non-zero if no match could be found. If you're also using
SNIPTYPE.H, you can therefore use the following:
DOSFileData ff_info;
char fname[];
int AttributeMask;
if (Success_ == FIND_FIRST(fname, AttributeMask, &ff_info))
{
/* Do found it stuff here */
}
else
{
/* Do no match stuff here */
}
The attribute mask bits follow standard Microsoft practice and are defined in
DIRPORT.H as:
_A_NORMAL All "normal" (i.e. none of the special types below) files.
_A_RDONLY File cannot be written, only read.
_A_HIDDEN File will not show up in a normal directory listing.
_A_SYSTEM File is used by the system and cannot be moved.
_A_SUBDIR The specification describes a subdirectory.
_A_VOLID The file name is the volume ID (obsolescent).
_A_ARCH File has been modified since last backed up.
_A_ANY Any/all of the above.
The attribute masks are bitwise additive (see Note 1 below) and somewhat
counter-intuitive in their operation. With the exception of the obsolescent
_A_VOLID attribute, specifying any mask bit returns all files of that type
matching the specification *PLUS* all "normal" files as well. If you
therefore want to see only the subdirectories, you must use the _A_SUBDIR
mask and then check each return file to see if it really is a subdirectory or
simply another normal file.
As noted, specifying the _A_VOLID mask by itself will return only files with
the volume ID attribute set. The volume ID was originally used to store the
disk's "name", but that has been stored in sector zero since DOS 5 (see
Note 2 below). The only use for the volume ID attribute in current versions
of DOS is for reading pre-DOS 5 diskettes and in the specification of long
file names under Windows 95.
Once you've found a match, you access the returned information using the
following macros defined in DIRPORT.H:
ff_name() The name, minus path information, of the file found.
ff_size() The size, in bytes, of the file found.
ff_attr() The attributes of the file found.
ff_date() The last modified date of the file found.
ff_yr() The year specified in ff_date().
ff_mo() The month specified in ff_date().
ff_day() The day specified in ff_date().
ff_time() The last modified time of the file found.
ff_hr() The hours specified in ff_time().
ff_min() The minutes specified in ff_time().
ff_tsec() The seconds divided by two specified in ff_time().
Note that each is passed the address of the DOSFileData structure where
FIND_FIRST() told the OS to store resulting information, e.g.
file_size = ff_size(&ff_info);
As noted, the file name is the file's name within its own directory, i.e. no
drive or path information is available. If you need drive and/or path infor-
mation, you must have saved it when forming the filename specification, e.g.
char *path;
char file_spec[FILENAME_MAX];
char full_name[FILENAME_MAX];
DOSFileData ff_info;
sprintf(file_spec, "%s\\*.*", path);
if (Success_ == FIND_FIRST(file_spec, _A_ANY, &ff_info))
{
sprintf(full_name, "%s\\%s", path, ff_name(&ff_info));
}
Once you've found the first matching file, you can find other files matching
the specification (here we're assuming the original specification contained
wildcards) by calling the FIND_NEXT(buf) function. It takes as its only
argument, a pointer to the location of the DOSFileData structure and returns
0 if successful. Note that you can have several active directory processing
sessions in a program, each using a different DOSFileData structure.
Putting together the examples given so far, you could process all the normal
and read-only files plus subdirectories in the current directory as follows:
DOSFileData ff_info;
if (Success_ == FIND_FIRST("*.*", _A_RDONLY+_A_SUBDIR, &ff_info)) do
{
if (ff_attr(&ff_info) & _A_SUBDIR) /* Note use of bitwise AND! */
{
/* Process subdirectories here /
}
else
{
/* Process normal and read-only files here */
}
} while (Success_ == FIND_NEXT(&ff_info));
FIND_END(&ff_info);
Note that for compatibility with all supported OS's, when you're done with a
particular directory processing session, you should call the FIND_END()
function to clean up.
One final note... If using Win32 or OS/2, you must compile and link the
DIRPORT.C file with your applications.
-----------------------------------------------------------------------------
Notes:
1. Attribute masks may be formed by adding or or'ing together specific
attributes, e.g.
attr = _A_NORMAL + _A_RDONLY; /* This is OK */
attr = _A_NORMAL | _A_RDONLY; /* So is this */
However, when testing for specific attributes, you should always use the
& (bitwise AND) operator, e.g.
if (ff_attr(&ff_info) & _A_RDONLY)
*NEVER* use the && (logical AND) or == (equality) operators when testing
for file attributes!
2. Regarding volume ID's... Although the primary storage for the volume ID
has been in sector zero since the introduction of DOS 5, a single
directory entry with only the _A_VOLID bit set in the root directory is
still maintained for backwards compatibility. The file name of this
directory entry matches the volume ID as stored in disk sector 0.
written by: Bob Stout
rbs@brokersys.com
1:106/2000.6